package app.services;

import app.Const;
import app.constant.DictConstant;
import app.constant.OrderConstant;
import app.constant.ProductConstant;
import app.constant.TransferConstant;
import app.dtos.PayDto;
import app.exceptions.AmountException;
import app.kit.TypeKit;
import app.models.analyze.ProductRecord;
import app.models.member.Account;
import app.models.member.AccountAmount;
import app.models.member.MemberProduct;
import app.models.order.Order;
import app.models.order.TradeMoney;
import app.models.product.Product;
import app.models.transfer.TransferProduct;
import bank.BankService;
import bank.resp.OrderInfoRspDto;
import com.google.common.base.Optional;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import goja.Logger;
import goja.StringPool;
import goja.plugins.sqlinxml.SqlKit;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

import static app.Const.FIELD_MEMBER;
import static app.Const.FIELD_NAME;
import static app.Const.FIELD_ORDER_ID;
import static app.Const.FIELD_PRODUCT;
import static app.Const.FIELD_STATUS;
import static app.Const.FIELD_TIME_LIMIT;
import static app.Const.FIELD_TIME_LIMIT_UNIT;
import static app.Const.FIELD_TIME_TERM;
import static app.Const.FIELD_YIELD;
import static app.constant.MemberConstant.PRODUCT_HOLDING;
import static app.constant.MemberConstant.PRODUCT_SALE;
import static app.constant.MemberConstant.PRODUCT_SALES_SUCCESS;

/**
 * <p>
 * 交易服务，包括容错处理
 * </p>
 *
 * @author sogYF
 * @version 1.0
 * @since JDK 1.6
 */
public final class TradeService {

    /**
     * 单例服务
     */
    public static final TradeService me = new TradeService();

    /**
     * 扫描订单
     * <p/>
     * 1. 扫描所有待支付的订单信息
     * 2. 通过银行订单信息状态接口
     * 3. 判断订单产品的状态
     * 4-1. 如果产品状态为成立\募集失败\销售到期\已结束\售罄,则算交易失败
     * 4-2. 如果交易失败，则产生交易失败打款单
     * 5-1. 如果产品状态为上线销售中，则订单交易成功，
     * 5-2. 新增会员产品信息和消费纪录
     */
    public void scanOrder() {
        // 1. 扫描一段时间内的订单
        // 总共多少待支付的订单
        long totalRownum = Order.dao.countOrderPaySize();
        Logger.info("The number of orders to be paid for {}", totalRownum);
        DateTime now = DateTime.now();
        if (totalRownum > 0) {
            // 每次处理50条纪录
            int totalPage = (int) totalRownum / 50;
            if (totalRownum % 50 != 0) {
                totalPage++;
            }
            for (int i = 1; i <= totalPage; i++) {
                //  存在待支付的订单
                Product product;
                String tradeNo;
                int productId;
                int productStatus;
                List<Order> orderList = Order.dao.findByStatus(i, OrderConstant.TOBEPAY, 50);
                for (final Order order : orderList) {
                    tradeNo = order.getStr("trade_no");
                    productId = TypeKit.getInt(order, Const.FIELD_PRODUCT);
                    product = Product.dao.findById(productId);
                    if (product == null) {
                        Logger.info("the project {} is null.", productId);
                        continue;
                    }
                    productStatus = TypeKit.getStatus(product);
                    if (productStatus == -1) {
                        Logger.info("the project {} status has error!", product.toJson());
                        continue;
                    }
                    int transferProductId = TypeKit.getInt(order, "transfer_product");
                    int transferProductStatus = 0;
                    if (transferProductId > 0) {
                        TransferProduct transferProduct = TransferProduct.dao.findById(transferProductId);
                        transferProductStatus = TypeKit.getStatus(transferProduct);
                    }
                    // 检测银行接口
                    Optional<OrderInfoRspDto> orderInfo = BankService.me.getOrderInfo(now, now, tradeNo);
                    if (orderInfo.isPresent()) {
                        // 银行返回信息
                        OrderInfoRspDto orderInfoRspDto = orderInfo.get();
                        if (orderInfoRspDto.isSuccess()) {
                            int orderStatus = orderInfoRspDto.getOrderStatus();
                            if (orderStatus == OrderConstant.TRADE_SUCCESS) {
                                // 交易成功
                                switch (productStatus) {
                                    case ProductConstant.ONLINE:
                                        // 产品还在销售期
                                        order.set(Const.FIELD_STATUS, OrderConstant.TRADE_SUCCESS);

                                        final Product buy_product = Product.dao.findById(productId);
                                        try {
                                            pay(PayDto.create(orderInfoRspDto), order, buy_product);
                                        } catch (AmountException ae) {
                                            // 交易失败
//                                            order.set(Const.FIELD_STATUS, OrderConstant.TRADE_SUCCESS);
                                            order.set("remark", "支付金额超过产品募集可投资金，无法完成交易，银行为支付成功，平台默认交易失败");
                                            //  生成交易失败打款纪录
                                            final TradeMoney tradeMoney = TradeMoney.payFail(productId, orderInfoRspDto.getAmount(),
                                                    order.getStr("membercode"), TypeKit.getInt(order, "member"), order);
                                            Db.tx(new IAtom() {
                                                @Override
                                                public boolean run() throws SQLException {
                                                    return tradeMoney.save() && order.update();
                                                }
                                            });
                                        }
                                        break;
                                    default:
                                        // 产品成立到起息之间，如果是转让产品
                                        if (productStatus == ProductConstant.FOUND && transferProductId > 0) {
                                            if (transferProductStatus == TransferConstant.STATUE_TRADING) {
                                                // 转让产品信息
                                                final TransferProduct transferProduct = TransferProduct.dao.findByAllInfo(transferProductId);
                                                TransferService.me.transfer(PayDto.create(orderInfoRspDto), order, transferProduct);
                                            }
                                        } else {
                                            order.set(Const.FIELD_STATUS, OrderConstant.TRADE_SUCCESS);
                                            //  生成交易失败打款纪录
                                            final TradeMoney tradeMoney = TradeMoney.payFail(productId, orderInfoRspDto.getAmount(),
                                                    order.getStr("membercode"), TypeKit.getInt(order, "member"), order);
                                            Db.tx(new IAtom() {
                                                @Override
                                                public boolean run() throws SQLException {
                                                    return tradeMoney.save() && order.update();
                                                }
                                            });
                                        }
                                }
                                // 对单条对账信息发起对账
                                CheckAccountService.me.checkAccount(order,orderInfoRspDto);
                            }
                        }
                    }
                }
            }

        }

    }


    public boolean pay(PayDto payDto, final Order order, final Product buy_product) {
        BigDecimal totalAmount = payDto.totalAmount;
        DateTime resp_date = payDto.respBizDate;

        final int productId = TypeKit.getInt(buy_product, StringPool.PK_COLUMN);
        // 会员信息
        final int memberId = TypeKit.getInt(order, FIELD_MEMBER);
        // 更新产品信息 金额 会修改产品状态哦
        final int collection_mode = buy_product.getCollectionMode();
        final float yield = TypeKit.getFloat(buy_product, FIELD_YIELD);
        buy_product.updateBuy(totalAmount);
        // 会员产品
        final MemberProduct memberProduct = MemberProduct.buildBuyProduct(memberId, productId, totalAmount, resp_date, collection_mode, yield);

//        memberProduct.set("term", 0);
        // 产品起息日模式
        final int valuedate_offset = TypeKit.getInt(buy_product, "valuedate_offset");
        DateTime startDate;
        // 起息日按照 成交日方式来处理
        // 是否成交
        final boolean deal_ok;
        // 会员产品状态
        if (collection_mode == DictConstant.PROFIT_ROLL) {
            // 本息滚动投资，宝宝类产品
            // 本息滚动投资在到期时间，只有金额为0，那么表示为空
            rollProfitMemberProduct(memberProduct, valuedate_offset);
            deal_ok = false;
        } else {

            int productStatus;
            //  计算起息时间
            final Timestamp db_vd = buy_product.getTimestamp("valuedate");
            //  起息日期
            if (db_vd == null) {
                // 起息日期不存在，则采用 成交日方式计算起息
                memberProduct.set(FIELD_TIME_TERM, 0);

            } else {
                startDate = new DateTime(db_vd.getTime());
//                if (valuedate_offset > 0) {
//                    // 非T＋0
//                    startDate = startDate.plusDays(valuedate_offset);
//                }

                // 计算到期时间
                // 理财期限
                final int time_limit = TypeKit.getInt(buy_product, FIELD_TIME_LIMIT);
                final String time_limit_unit = buy_product.getStr(FIELD_TIME_LIMIT_UNIT);
                DateTime dueDate;
                if (StringUtils.equals(time_limit_unit, DictConstant.MONTH_UNIT)) {
                    //  理财期限单位为月
                    dueDate = startDate.plusMonths(time_limit);
                } else {
                    dueDate = startDate.plusDays(time_limit);
                }
                // 总共多少天
                memberProduct.set(FIELD_TIME_TERM, Days.daysBetween(startDate, dueDate).getDays());
                memberProduct.set("due_time", dueDate);
                memberProduct.set("due_time_year", dueDate.getYear());
                memberProduct.set("due_time_month", dueDate.getMonthOfYear());
                memberProduct.set("due_time_day", dueDate.getDayOfMonth());

                memberProduct.set("valuedate", startDate);
                memberProduct.set("valuedate_year", startDate.getYear());
                memberProduct.set("valuedate_month", startDate.getMonthOfYear());
                memberProduct.set("valuedate_day", startDate.getDayOfMonth());
            }


            // 成交OK，在Product中计算得出来的(成交就是售罄）

            deal_ok = TypeKit.getStatus(buy_product) == ProductConstant.EMPTY;
            productStatus = deal_ok ? PRODUCT_SALES_SUCCESS : PRODUCT_SALE;

            memberProduct.set(MemberProduct.FIELD_PRODUCT_STATUS, productStatus);

        }
        memberProduct.set(FIELD_ORDER_ID, TypeKit.getInt(order, StringPool.PK_COLUMN));

        //  更新订单状态
        order.set(FIELD_STATUS, payDto.orderStatus);
        // 以银行返回信息为主
        order.set("trade_amount", totalAmount);
        order.set("fee_amonut", payDto.fee);
        final DateTime now = DateTime.now();
        order.set("confirm_date", now);
        // 记录资金记录
        final AccountAmount accountAmount = AccountAmount.dao.buyExpense(memberId, buy_product.getStr(FIELD_NAME),
                resp_date, totalAmount);


        // 更新会员账户信息
        final Account account = AccountService.me.calculationAccount(totalAmount, memberId);

        // 2015-04-14 积分在募集成功后进行赠送

        // 写入购买纪录
        final ProductRecord record = new ProductRecord();
        record.set(FIELD_PRODUCT, productId);
        record.set("investor", memberId);
        record.set("investor_amount", totalAmount);
        record.set("investor_time_year", now.getYear());
        record.set("investor_time_month", now.getMonthOfYear());
        record.set("investor_time_day", now.getDayOfMonth());
        record.set("investor_time", now);
        record.set("integral", 0);

        return Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                boolean memberProductDeal = true;
                if (deal_ok) {
                    // 更新所有会员的募集中的产品状态
                    memberProductDeal =
                            Db.update(SqlKit.sql("memberproduct.updateByProductStatus"), PRODUCT_SALES_SUCCESS, productId, PRODUCT_SALE) >= 0;
                }
                if (memberProductDeal) {
                    return memberProduct.save()
                            && order.update()
                            && accountAmount.save()
                            && buy_product.update()
                            && record.save()
                            && account.update();
                }
                return false;
            }
        });

    }


    /**
     * 设置 本息滚动投资(宝宝类产品） 的会员产品的 起息时间
     *
     * @param memberProduct    会员产品
     * @param valuedate_offset 起息模式
     */
    public void rollProfitMemberProduct(final MemberProduct memberProduct, int valuedate_offset) {
        DateTime startDate = DateTime.now();
        //  期限0 表示 永不过期
        memberProduct.set(FIELD_TIME_TERM, 0);

        if (valuedate_offset > 0) {
            // 非T＋0
            startDate = startDate.plusDays(valuedate_offset);
        }

        memberProduct.set("valuedate", startDate);
        memberProduct.set("valuedate_year", startDate.getYear());
        memberProduct.set("valuedate_month", startDate.getMonthOfYear());
        memberProduct.set("valuedate_day", startDate.getDayOfMonth());
        memberProduct.set("product_status", PRODUCT_HOLDING);
    }

}
